/*
* @(#)EmailDeliveryMessage.java
*
* Copyright (c) 2003 DCIVision Ltd
* All rights reserved.
*
* This software is the confidential and proprietary information of DCIVision
* Ltd ("Confidential Information").  You shall not disclose such Confidential
* Information and shall use it only in accordance with the terms of the license
* agreement you entered into with DCIVision Ltd.
 */
package com.dcivision.framework.notification;

import java.io.UnsupportedEncodingException;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.activation.DataHandler;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.dcivision.framework.ApplicationException;
import com.dcivision.framework.SystemParameterConstant;
import com.dcivision.framework.SystemParameterFactory;
import com.dcivision.framework.TextUtility;
import com.dcivision.framework.bean.GenericAddress;

/**
 * <p>Class Name:       EmailDeliveryMessage.java    </p>
 * <p>Description:      This class implements DeliveryMessage, is used to setup the email sender and addressee information, </p>
 * <p>                  and resolve the email content ready for delivery. </p>
 *
 * @author           Zoe Shum
 * @company          DCIVision Limited
 * @creation date    02/07/2003
 * @version          $Revision: 1.15.4.2 $
 */
public class EmailDeliveryMessage implements DeliveryMessage {

  public static final String REVISION = "$Revision: 1.15.4.2 $";

  private static final Log log = LogFactory.getLog(EmailDeliveryMessage.class);

  //protected Log gLog = LogFactory.getLog(this.getClass().getName());
  public static final String CONTENT_TYPE_HTML = "text/html";
  public static final String CONTENT_TYPE_PLAIN = "text/plain";

  private GenericAddress m_Sender;
  private GenericAddress[] m_aReplyTo;
  private List m_lToList;
  private List m_lccList;
  private List m_lbccList;
  private String m_sSubject = "";
  private String m_sContent = "";
  private String m_sCharset = SystemParameterFactory.getSystemParameter(SystemParameterConstant.ENCODING);
  private String m_sContentType = "text/plain";
  private Map m_mAttachmentMap;
  private Session m_Session;

  /**
   *  Constructor - initiate the global variable.
   *
   *  @param      No parameter needed
   *  @return     No return value
   *  @throws     No exception throws
   */
  public EmailDeliveryMessage() {
    m_lToList = new ArrayList();
    m_lccList = new ArrayList();
    m_lbccList = new ArrayList();
    m_mAttachmentMap = new HashMap();
  }

  /**
   *  Method setSender() - set the sender information in GenericAddress.
   *
   *  @param      sender                      The GenericAddress for sender info.
   *  @return     No return value
   *  @throws     No exception throws
   */
  public void setSender(GenericAddress sender) {
    this.m_Sender = sender;
  }

  /**
   *  Method getSender() - retrieves the sender information in GenericAddress.
   *
   *  @param      No pass in paramter needed
   *  @return     GenericAddress                The GenericAddress for sender info.
   *  @throws     No exception throws
   */
  public GenericAddress getSender() {
    return m_Sender;
  }

  /**
   *  Method setReplyTo() - set the addressee of Reply-To information
   *                        in array of GenericAddress.
   *
   *  @param      aReplyTo                The array of GenericAddress contains addressee in Reply-To list
   *  @return     No return value
   *  @throws     No exception throws
   */
  public void setReplyTo(GenericAddress[] aReplyTo) {
    this.m_aReplyTo = aReplyTo;
  }

  /**
   *  Method getReplyTo() - retrieves the addressee of Reply-To information
   *                        in array of GenericAddress.
   *
   *  @param      No pass in paramter needed
   *  @return     GenericAddress[]             The array of GenericAddress contains addressee in Reply-To List
   *  @throws     No exception throws
   */
  public GenericAddress[] getReplyTo() {
    return m_aReplyTo;
  }

  /**
   *  Method addToRecipient() - add the addressee of Recipient information
   *                            into the array of GenericAddress.
   *
   *  @param      toRecipient                 The GenericAddress that contains recipient info
   *  @return     No return value
   *  @throws     No exception throws
   */
  public void addToRecipient(GenericAddress toRecipient) {
    m_lToList.add(toRecipient);
  }

  /**
   *  Method setToRecipientList() - set the addressee of Recipient List
   *                                in GenericAddress.
   *
   *  @param      lToList                    The list of GenericAddress contains addressee in To list
   *  @return     No return value
   *  @throws     No exception throws
   */
  public void setToRecipientList(List lToList) {
    this.m_lToList = lToList;
  }

  /**
   *  Method getToRecipientList() - retrieves the addressee of Recipient
   *                                in list of GenericAddress.
   *
   *  @param      No pass in paramter needed
   *  @return     List                         The list of GenericAddress contains addressee in To list
   *  @throws     No exception throws
   */
  public List getToRecipientList() {
    return m_lToList;
  }

  /**
   *  Method getToRecipientArray() - retrieves the addressee of Recipient
   *                                 in array of GenericAddress.
   *
   *  @param      No pass in paramter needed
   *  @return     GenericAddress[]             The array of GenericAddress contains addressee in To list
   *  @throws     No exception throws
   */
  public GenericAddress[] getToRecipientArray() {
    GenericAddress[] ias = new GenericAddress[m_lToList.size()];
    System.arraycopy(m_lToList.toArray(), 0, ias, 0, m_lToList.size());
    return ias;
  }

  /**
   *  Method addCCRecipient() - add the addressee of CCRecipient
   *                            into the CCRecipient List.
   *
   *  @param      ccRecipient            The GenericAddress of CC recipeint info
   *  @return     No return value
   *  @throws     No exception throws
   */
  public void addCCRecipient(GenericAddress ccRecipient) {
    m_lccList.add(ccRecipient);
  }

  /**
   *  Method setCCRecipientList() - set the addressee of CCRecipient List
   *                                in List.
   *
   *  @param      lccList                  The list of GenericAddress contains addressee for CC Recipient list
   *  @return     No return value
   *  @throws     No exception throws
   */
  public void setCCRecipientList(List lccList) {
    this.m_lccList = lccList;
  }

  /**
   *  Method getCCRecipientList() - retrieves the addressee of CCRecipient List
   *                                in of GenericAddress.
   *
   *  @param      No pass in parameter needed
   *  @return     List                        The list of GenericAddress contains addressee for CC Recipient list
   *  @throws     No exception throws
   */
  public List getCCRecipientList() {
    return m_lccList;
  }

  /**
   *  Method getCCRecipientArray() - retrieves the addressee of CCRecipient Array
   *                                 in of GenericAddress.
   *
   *  @param      No pass in paramter needed
   *  @return     GenericAddress[]           The array of GenericAddress contains addressee for CC Recipient list
   *  @throws     No exception throws
   */
  public GenericAddress[] getCCRecipientArray() {
    GenericAddress[] ias = new GenericAddress[m_lccList.size()];
    System.arraycopy(m_lccList.toArray(), 0, ias, 0, m_lccList.size());
    return ias;
  }

  /**
   *  Method addBCCRecipient() - add the addressee of BCCRecipient
   *                             into BCCRecipient List.
   *
   *  @param      bccRecipient              The GenericAddress of addressee for BCC Recipient
   *  @return     No return value
   *  @throws     No exception throws
   */
  public void addBCCRecipient(GenericAddress bccRecipient) {
    m_lbccList.add(bccRecipient);
  }

  /**
   *  Method setBCCRecipi() - set the addressee of BCCRecipient List
   *                          in GenericAddress.
   *
   *  @param      lbccList                   The list of GenericAddress contains addressee for BCC Recipient list
   *  @return     No return value
   *  @throws     No exception throws
   */
  public void setBCCRecipientList(List lbccList) {
    this.m_lbccList = lbccList;
  }

  /**
   *  Method getBCCRecipientArray() - retrieves the addressee of BCCRecipient Array
   *                                  in GenericAddress.
   *
   *  @param      No pass in paramter needed
   *  @return     GenericAddress[]            The array of GenericAddress contains addressee for BCC Recipient list
   *  @throws     No exception throws
   */
  public GenericAddress[] getBCCRecipientArray() {
    GenericAddress[] ias = new GenericAddress[m_lbccList.size()];
    System.arraycopy(m_lbccList.toArray(), 0, ias, 0, m_lbccList.size());
    return ias;
  }

  /**
   *  Method getBCCRecipientList() - retrieves the addressee of BCCRecipient List
   *                                 in GenericAddress.
   *
   *  @param      No pass in paramter needed
   *  @return     List                           The list of GenericAddress contains addressee for BCC Recipient list
   *  @throws     No exception throws
   */
  public List getBCCRecipientList() {
    return m_lbccList;
  }

  /**
   *  Method setSubject() - set the subject of email.
   *
   *  @param      sSubject                      The subject of email
   *  @return     No return value
   *  @throws     No exception throws
   */
  public void setSubject(String sSubject) {
    this.m_sSubject = sSubject;
  }

  /**
   *  Method getSubject() - retrieves the subject of email.
   *
   *  @param      No pass in paramter needed
   *  @return     String                         The subject of email
   *  @throws     No exception throws
   */
  public String getSubject() {
    return m_sSubject;
  }

  /**
   *  Method setMailContent() - set the content of email to be send.
   *
   *  @param      sContent                    The email content
   *  @return     No return value
   *  @throws     No exception throws
   */
  public void setMailContent(String sContent) {
    this.m_sContent = sContent;
  }

  /**
   *  Method getMailContent() - retrieves the content of email.
   *
   *  @param      No pass in paramter needed
   *  @return     String                       The email content
   *  @throws     No exception throws
   */
  public String getMailContent() {
    return m_sContent;
  }

  /**
   *  Method setCharset() - set the default character set of email.
   *
   *  @param      sCharset                 The character set of email
   *  @return     No return value
   *  @throws     No exception throws
   */
  public void setCharset(String sCharset) {
    this.m_sCharset = sCharset;
  }

  /**
   *  Method getCharset() - retrieves the character set of email.
   *
   *  @param      No pass in paramter needed
   *  @return     String                      The character set of email
   *  @throws     No exception throws
   */
  public String getCharset() {
    return m_sCharset;
  }

  /**
   *  Method setContentType() - set the content type of email.
   *
   *  @param      sContentType              The content type of email
   *  @return     No return value
   *  @throws     No exception throws
   */
  public void setContentType(String sContentType) {
    this.m_sContentType = sContentType;
  }

  /**
   *  Method getContentType() - retrieves the content type of email.
   *
   *  @param      No pass in paramter needed
   *  @return     String                        The content type of email
   *  @throws     No exception throws
   */
  public String getContentType() {
    return m_sContentType;
  }

  /**
   *  Method addAttachment() - add the data file for email attachment.
   *
   *  @param      sName                   The name of attachment
   *  @param      abyteData               The array of byte Data Source of attachment
   *  @return     No return value
   *  @throws     No exception throws
   */
  public void addAttachment(String sName, byte[] abyteData) {
    m_mAttachmentMap.put(sName, abyteData);
  }

  /**
   *  Method addAttachment() - add the data file for email attachment.
   *
   *  @param       sName
   *  @param       is
   *  @return     No return value
   *  @throws     No exception throws
   */
  public void addAttachment(String sName, java.io.InputStream is) {
    m_mAttachmentMap.put(sName, is);
  }
  
  /**
   *  Method getAttachmentMap() - retrieves the attachment map.
   *
   *  @param      No pass in paramter needed
   *  @return     Map                       The Map used in email delivery attachments
   *  @throws     No exception throws
   */
  public Map getAttachmentMap() {
    return this.m_mAttachmentMap;
  }  

  /**
   *  Method setSession() - set the session.
   *
   *  @param      session                     The Session used in email delivery
   *  @return     No return value
   *  @throws     No exception throws
   */
  public void setSession(Session session) {
    this.m_Session = session;
  }

  /**
   *  Method getSession() - retrieves the session.
   *
   *  @param      No pass in paramter needed
   *  @return     Session                       The Session used in email delivery
   *  @throws     No exception throws
   */
  public Session getSession() {
    return m_Session;
  }

  /**
   *  Method getResolvedMessage() - retrieves the resolved email information, including sender
   *                                addressee, subject and attachment.
   *
   *  @param      No pass in paramter needed
   *  @return     Object                            The resolved message that ready to send
   *  @throws     ApplicationException              Throws ApplicationException if the email information resolve failed
   */
  public Object getResolvedMessage() throws ApplicationException {
    MimeMessage msg = new MimeMessage(m_Session);
    try {
      msg.setFrom(m_Sender);
      msg.setReplyTo(m_aReplyTo);
      msg.setRecipients(Message.RecipientType.TO, getToRecipientArray());
      msg.setRecipients(Message.RecipientType.CC, getCCRecipientArray());
      msg.setRecipients(Message.RecipientType.BCC, getBCCRecipientArray());
      msg.setSubject(m_sSubject,this.m_sCharset);
      msg.setSentDate(new Date());
      Multipart mp = new MimeMultipart();
      Multipart mp2 = new MimeMultipart("alternative");

      MimeBodyPart textPart = new MimeBodyPart();
      MimeBodyPart htmlPart = new MimeBodyPart();
      if (this.CONTENT_TYPE_HTML.equals(this.getContentType())) {
        textPart.setContent(TextUtility.htmlToPlainText(m_sContent,true), CONTENT_TYPE_PLAIN + ";charset="+this.m_sCharset);
        htmlPart.setContent(m_sContent, CONTENT_TYPE_HTML + ";charset="+this.m_sCharset);
      } else {
        textPart.setContent(m_sContent, CONTENT_TYPE_PLAIN + ";charset="+this.m_sCharset);
        htmlPart.setContent(TextUtility.br(m_sContent), CONTENT_TYPE_HTML + ";charset="+this.m_sCharset);
      }
      mp2.addBodyPart(textPart);
      mp2.addBodyPart(htmlPart);
      MimeBodyPart mbp1 = new MimeBodyPart();
      mbp1.setContent(mp2);
      mp.addBodyPart(mbp1);

//            mp.addBodyPart(htmlPart);

      Set attachKeySet = m_mAttachmentMap.keySet();
      for (Iterator iterator = attachKeySet.iterator(); iterator.hasNext();) {
        String fileName = (String) iterator.next();
        ByteArrayDataSource bads = null;
        MimeBodyPart dataPart = new MimeBodyPart();

        String fileContentType = URLConnection.guessContentTypeFromName(fileName) != null ?
                                 URLConnection.guessContentTypeFromName(fileName) : "application/octet-stream";

        if (m_mAttachmentMap.get(fileName) instanceof byte[]) {
          byte[] data = (byte[]) m_mAttachmentMap.get(fileName);
          bads = new ByteArrayDataSource(data, fileContentType);
        } else {
          java.io.InputStream is = (java.io.InputStream) m_mAttachmentMap.get(fileName);
          bads = new ByteArrayDataSource(is, fileContentType);
        }
        
        sun.misc.BASE64Encoder enc = new sun.misc.BASE64Encoder();//barbin 2006-5-10
        dataPart.setDataHandler(new DataHandler(bads));
        //dataPart.setFileName("=?GBK?B?"+enc.encode(fileName.getBytes())+"?=");//barbin 2005-5-10
        String dataPartName = MimeUtility.encodeWord(fileName, "utf-8",null);
        String[] names = dataPartName.split("\\?=");
        if( names.length > 1 ) {
          String tmpName = "";
          for( int i = 0 ; i < names.length ; i ++ ) {
            tmpName += names[i].substring(names[i].indexOf("B?")+2);
          }
          tmpName = names[0].substring(0,names[0].indexOf("B?")+2) + tmpName + "?=";
          dataPart.setFileName(tmpName);
        } else {
          dataPart.setFileName(dataPartName);
        }
        mp.addBodyPart(dataPart);
      }

      msg.setContent(mp);
    }
    catch (MessagingException me) {
      //gLog.error("Message Error="+me);
      log.error(me, me);
      throw new ApplicationException(me);
    }
    catch (UnsupportedEncodingException e) {
        //gLog.error("Message Error="+me);
      log.error(e, e);
        throw new ApplicationException(e);
      } 
    return msg;
  }
}